Skip to main content

use Keyword

The use keyword brings a path into the current scope.

Instead of writing long paths like:

crate::math::operations::add

everywhere, you can write:

use crate::math::operations::add;

and then just call:

add(2, 3);

use does not create or move code.
It only creates a shortcut (alias) to an existing item.

Where use Fits in Project Structure

Recall the hierarchy:

Crate
└── Modules
└── Items (functions, structs, enums, traits)

use works at any level to:

  • import items from modules
  • import items from other crates
  • improve readability and API design

Basic Example: Without vs With use

Project structure

src/
├── main.rs
└── math.rs

math.rs

pub fn add(a: i32, b: i32) -> i32 {
a + b
}

Without use

mod math;

fn main() {
println!("{}", math::add(2, 3));
}

With use

mod math;
use math::add;

fn main() {
println!("{}", add(2, 3));
}
  • use math::add; brings add into scope
  • Cleaner and easier to read

Importing from Nested Modules

Structure

src/
├── main.rs
└── math/
├── mod.rs
└── operations.rs

math/mod.rs

pub mod operations;

math/operations.rs

pub fn add(a: i32, b: i32) -> i32 {
a + b
}

main.rs

mod math;
use math::operations::add;

fn main() {
println!("{}", add(5, 3));
}

use with External Crates

Cargo.toml

[dependencies]
rand = "0.8"

Importing

use rand::Rng;

fn main() {
let n = rand::thread_rng().gen_range(1..=10);
println!("{}", n);
}
  • rand is an external crate
  • use rand::Rng; imports a trait
  • Required so .gen_range() works

use and Visibility Rules

use does not bypass privacy.

mod secret {
fn hidden() {}
}
use secret::hidden; // ❌ error: private function

To fix:

mod secret {
pub fn hidden() {}
}

use secret::hidden; // ✅

use with crate, self, and super

crate:: – from crate root

use crate::math::add;

self:: – current module

use self::helpers::log;

super:: – parent module

use super::config::Settings;

Grouped Imports (Clean & Idiomatic)

Without grouping

use std::fs::File;
use std::io::Read;
use std::io::Write;

With grouping

use std::io::{Read, Write};
use std::fs::File;

Glob Imports (*) – Use Carefully

use std::collections::*;

Pros

  • Less typing
  • Useful in tests or small modules

Cons

  • Can cause name conflicts
  • Reduces readability

Best practice: Avoid in public APIs.

Aliasing with as

Use aliases when names collide or are too long.

use std::io::Result as IoResult;

fn read_file() -> IoResult<()> {
Ok(())
}

Another example (name conflict)

use std::fmt::Result;
use std::io::Result as IoResult;

Re-exporting with pub use

This is very important for library design.

Example: Re-exporting API

src/
├── lib.rs
└── internal.rs

internal.rs

pub struct User {
pub name: String,
}

lib.rs

mod internal;
pub use internal::User;

Usage

use my_lib::User;

Why this matters

  • Hides internal module structure
  • Creates a clean public API
  • Common in professional Rust libraries

use Scope Rules

A use statement applies:

  • only to the module it is written in
  • not automatically to submodules
mod a {
use crate::utils::log;
}

mod b {
// log is NOT available here
}

Idiomatic Placement of use

Rust convention:

use std::fs::File;
use std::io::{Read, Write};

fn main() {
// logic here
}
  • Place use statements at the top of the module
  • After mod declarations
  • Before code

use vs mod (Common Confusion)

KeywordPurpose
modDefines or loads a module
useImports items into scope
mod math;        // declares module
use math::add; // imports function

Real-World Example (Binary + Library)

Structure

src/
├── main.rs
├── lib.rs
└── auth/
├── mod.rs
└── login.rs

lib.rs

pub mod auth;

auth/login.rs

pub fn login() {
println!("Login successful");
}

main.rs

use my_app::auth::login::login;

fn main() {
login();
}